今天是藍牙開發實作的最終篇,我們將完整展示這個專案的三個核心組成:MainViewController、BluetoothTableViewCell 以及 BluetoothService。這次的重點不在於新增功能,而是將所有元件整合起來,讓大家能清楚看到 XIB 與程式碼之間如何協同運作。
在 MainViewController 裡,我們主要負責管理藍牙設備的列表顯示、接收資料並即時更新介面。畫面中以 UITableView 呈現所有可偵測到的周邊設備,搭配 UILabel 顯示光線感測數據的即時變化,整體結構清晰又易於擴充。
而 BluetoothTableViewCell 則是自訂的表格元件,負責顯示每個藍牙設備的名稱,搭配簡潔的 XIB 佈局讓 UI 一目了然。
最後的 BluetoothService 是整個專案的靈魂。它透過 CoreBluetooth 框架進行藍牙掃描、連線、資料訂閱與數據回傳,並利用 delegate 機制與畫面進行資料交換。這樣的架構不僅模組化,後續若要擴充更多藍牙互動功能也相當方便。
這次展示完整的程式結構,讓你能從介面到邏輯一次掌握,了解一個具備即時資料顯示能力的藍牙應用是如何誕生的。

//
// MainViewController.swift
// Bluetooth
//
// Created by imac-2156 on 2025/8/15.
//
import UIKit
import CoreBluetooth
class MainViewController: UIViewController {
// MARK: - IBOutlet(介面連接)
@IBOutlet weak var tableView: UITableView!
// 顯示藍牙設備列表的表格視圖
@IBOutlet weak var lbLightNumber: UILabel!
// 顯示接收數據的標籤
// MARK: - Property(屬性)
private var peripherals: [CBPeripheral] = [] // 儲存發現的藍牙設備
private var connectedPeripheral: CBPeripheral? // 當前連接的設備
// MARK: - LifeCycle(生命週期)
override func viewDidLoad() {
super.viewDidLoad()
setUI() // 設置介面
BluetoothService.shared.delegate = self // 設置藍牙服務代理
}
// MARK: - UI Settings(介面設置)
func setUI() {
tableView.delegate = self // 設置表格視圖代理
tableView.dataSource = self // 設置表格視圖數據源
// 註冊表格單元格
tableView.register(UINib(nibName: "BluetoothTableViewCell", bundle: nil), forCellReuseIdentifier: "BluetoothTableViewCell")
lbLightNumber.text = "等待數據..." // 設置初始顯示文字
}
// MARK: - IBAction(介面操作)
// (目前沒有按鈕操作)
// MARK: - Function(自定義功能)
// (目前沒有額外功能)
}
// MARK: - Extensions(擴展)
// 藍牙服務代理實現
extension MainViewController: BluetoothServiceDelegate {
// 接收藍牙服務發現的設備列表
func getBLEPeripherals(peripherals: [CBPeripheral]) {
self.peripherals = peripherals // 更新本地設備列表
// 切換到主線程更新 UI
DispatchQueue.main.async {
self.tableView.reloadData() // 重新載入表格數據
}
}
// 接收從藍牙設備傳來的數據
func getBLEPeripheralsValue(value: String) {
// 切換到主線程更新 UI
DispatchQueue.main.async {
self.lbLightNumber.text = "光線強度:\(value)" // 顯示接收的數據
}
print("\(value)") // 在控制台打印數據
}
}
// 表格視圖代理與數據源實現
extension MainViewController: UITableViewDelegate, UITableViewDataSource {
// 返回表格行數
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return peripherals.count // 根據發現的設備數量決定行數
}
// 配置每一行的單元格
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// 取得可重用的單元格並轉型為自定義單元格
guard let cell = tableView.dequeueReusableCell(withIdentifier: "BluetoothTableViewCell", for: indexPath) as? BluetoothTableViewCell else {
return UITableViewCell()
}
let peripheral = peripherals[indexPath.row] // 取得對應的設備
// 設置單元格顯示的設備名稱
cell.lbName.text = peripheral.name ?? "未知設備"
return cell
}
// 處理用戶點擊某一行
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true) // 取消選中狀態
let selectedPeripheral = peripherals[indexPath.row] // 取得選中的設備
// 呼叫藍牙服務連接該設備
BluetoothService.shared.connectPeripheral(peripheral: selectedPeripheral)
}
}

//
// BluetoothTableViewCell.swift
// Bluetooth
//
// Created by imac-2156 on 2025/8/15.
//
import UIKit
class BluetoothTableViewCell: UITableViewCell {
@IBOutlet weak var lbName: UILabel!// 顯示設備名稱的標籤
// 當從 Storyboard 或 Xib 文件載入時調用
override func awakeFromNib() {
super.awakeFromNib()
// 在這裡進行初始化設置
}
// 當單元格被選中或取消選中時調用
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// 在這裡配置選中狀態的視覺效果
}
}
//
// MainViewController.swift
// Bluetooth
//
// Created by imac-2156 on 2025/8/15.
//
import UIKit
import CoreBluetooth
class MainViewController: UIViewController {
// MARK: - IBOutlet(介面連接)
@IBOutlet weak var tableView: UITableView!
// 顯示藍牙設備列表的表格視圖
@IBOutlet weak var lbLightNumber: UILabel!
// 顯示接收數據的標籤
// MARK: - Property(屬性)
private var peripherals: [CBPeripheral] = [] // 儲存發現的藍牙設備
private var connectedPeripheral: CBPeripheral? // 當前連接的設備
// MARK: - LifeCycle(生命週期)
override func viewDidLoad() {
super.viewDidLoad()
setUI() // 設置介面
BluetoothService.shared.delegate = self // 設置藍牙服務代理
}
// MARK: - UI Settings(介面設置)
func setUI() {
tableView.delegate = self // 設置表格視圖代理
tableView.dataSource = self // 設置表格視圖數據源
// 註冊表格單元格
tableView.register(UINib(nibName: "BluetoothTableViewCell", bundle: nil), forCellReuseIdentifier: "BluetoothTableViewCell")
lbLightNumber.text = "等待數據..." // 設置初始顯示文字
}
// MARK: - IBAction(介面操作)
// (目前沒有按鈕操作)
// MARK: - Function(自定義功能)
// (目前沒有額外功能)
}
// MARK: - Extensions(擴展)
// 藍牙服務代理實現
extension MainViewController: BluetoothServiceDelegate {
// 接收藍牙服務發現的設備列表
func getBLEPeripherals(peripherals: [CBPeripheral]) {
self.peripherals = peripherals // 更新本地設備列表
// 切換到主線程更新 UI
DispatchQueue.main.async {
self.tableView.reloadData() // 重新載入表格數據
}
}
// 接收從藍牙設備傳來的數據
func getBLEPeripheralsValue(value: String) {
// 切換到主線程更新 UI
DispatchQueue.main.async {
self.lbLightNumber.text = "光線強度:\(value)" // 顯示接收的數據
}
print("\(value)") // 在控制台打印數據
}
}
// 表格視圖代理與數據源實現
extension MainViewController: UITableViewDelegate, UITableViewDataSource {
// 返回表格行數
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return peripherals.count // 根據發現的設備數量決定行數
}
// 配置每一行的單元格
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// 取得可重用的單元格並轉型為自定義單元格
guard let cell = tableView.dequeueReusableCell(withIdentifier: "BluetoothTableViewCell", for: indexPath) as? BluetoothTableViewCell else {
return UITableViewCell()
}
let peripheral = peripherals[indexPath.row] // 取得對應的設備
// 設置單元格顯示的設備名稱
cell.lbName.text = peripheral.name ?? "未知設備"
return cell
}
// 處理用戶點擊某一行
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true) // 取消選中狀態
let selectedPeripheral = peripherals[indexPath.row] // 取得選中的設備
// 呼叫藍牙服務連接該設備
BluetoothService.shared.connectPeripheral(peripheral: selectedPeripheral)
}
}
)